package com.mas.session;

import jade.core.Agent;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;

import java.util.HashMap;
import java.util.Map;

import com.mas.common.AgentUtil;
import com.mas.resource.ResourceInfo;
import com.mas.session.state.AbstractState;
import com.mas.session.state.AcceptNewProposalSenderState;
import com.mas.session.state.CreateCounterProposal;
import com.mas.session.state.DoneExitSenderState;
import com.mas.session.state.ExitState;
import com.mas.session.state.FailureExit;
import com.mas.session.state.ProcessAcceptState;
import com.mas.session.state.ProcessIncomingCFP;
import com.mas.session.state.NewProposalProcessor;
import com.mas.session.state.RefuseExitState;
import com.mas.session.state.RejectExitSenderState;
import com.mas.session.state.RejectExitState;
import com.mas.session.state.WaitingForProposalResState;
import com.mas.strategey.Strategy;

public abstract class Session {

	private Map<String, AbstractState> stateMap;

	private AbstractState currentState;

	private String name;

	private boolean isAliveInd;

	private Strategy strategy;

	protected Agent agent;

	private int nextMsgID = 1;

	private boolean accepted;

	private String exitReason;

	public Session(Agent agent, String name) {
		this.setName(name);

		this.agent = agent;
		isAliveInd = true;
		initAllStates();
		currentState = null;
		accepted = false;
	}

	private void initAllStates() {
		stateMap = new HashMap<String, AbstractState>();

		stateMap.put(AcceptNewProposalSenderState.class.getName(),
				new AcceptNewProposalSenderState(this));
		stateMap.put(CreateCounterProposal.class.getName(),
				new CreateCounterProposal(this));
		stateMap.put(DoneExitSenderState.class.getName(),
				new DoneExitSenderState(this));
		stateMap.put(ExitState.class.getName(), new ExitState(this));
		stateMap.put(FailureExit.class.getName(), new FailureExit(this));
		stateMap.put(NewProposalProcessor.class.getName(),
				new NewProposalProcessor(this));
		stateMap.put(ProcessAcceptState.class.getName(),
				new ProcessAcceptState(this));
		stateMap.put(ProcessIncomingCFP.class.getName(),
				new ProcessIncomingCFP(this));
		stateMap
				.put(RefuseExitState.class.getName(), new RefuseExitState(this));
		stateMap.put(RejectExitSenderState.class.getName(),
				new RejectExitSenderState(this));
		stateMap
				.put(RejectExitState.class.getName(), new RejectExitState(this));
		// stateMap.put(WaitForDoneState.class.getName(), new WaitForDoneState(
		// this));
		stateMap.put(WaitingForProposalResState.class.getName(),
				new WaitingForProposalResState(this));

	}

	public AbstractState assignState(String stateName) {
		if (!stateMap.containsKey(stateName)) {
			throw new RuntimeException(
					"Error, state name does not exists. stateName=" + stateName);
		}
		currentState =  (AbstractState) stateMap.get(stateName);
		return currentState;
	}

	/**
	 * @return the currentState
	 */
	public AbstractState getCurrentState() {
		return currentState;
	}

	/**
	 * @param currentState
	 *            the currentState to set
	 */
	public void setCurrentState(AbstractState currentState) {
		this.currentState = currentState;
	}

	/**
	 * @return the stateMap
	 */
	public Map<String, AbstractState> getStateMap() {
		return stateMap;
	}

	/**
	 * @param message
	 * @throws FIPAException
	 * @see com.mas.session.state.AbstractState#acceptProposalError(jade.lang.acl.ACLMessage)
	 */
	public void acceptProposalError(ACLMessage message) throws FIPAException {
		currentState.acceptProposalError(message);
	}

	/**
	 * @param message
	 * @throws FIPAException
	 * @see com.mas.session.state.AbstractState#acceptProposalResponse(jade.lang.acl.ACLMessage)
	 */
	public void acceptProposalResponse(ACLMessage message) throws FIPAException {
		currentState.acceptProposalResponse(message);
	}

	/**
	 * @param message
	 * @see com.mas.session.state.AbstractState#NoAvailableResource(jade.lang.acl.ACLMessage)
	 */
	public void NoAvailableResource(ACLMessage message) throws FIPAException {
		currentState.NoAvailableResource(message);
	}

	/**
	 * @param message
	 */
	public void notUnderstandMsgContent(ACLMessage message, String specificMsg)
			throws FIPAException {
		currentState.notUnderstandMsgContent(message, specificMsg);
	}

	/**
	 * @param message
	 * @see com.mas.session.state.AbstractState#processIncomingCFPMsg(jade.lang.acl.ACLMessage)
	 */
	public void processIncomingCFPMsg(ACLMessage message) throws FIPAException {
		currentState.processIncomingCFPMsg(message);
	}

	/**
	 * @param message
	 * @see com.mas.session.state.AbstractState#proposalAccepted(jade.lang.acl.ACLMessage)
	 */
	public void proposalAccepted(ACLMessage message) throws FIPAException {
		currentState.proposalAccepted(message);
	}

	/**
	 * @param message
	 * @see com.mas.session.state.AbstractState#rejectProposalResponse(jade.lang.acl.ACLMessage)
	 */
	public void rejectProposalResponse(ACLMessage message) throws FIPAException {
		currentState.rejectProposalResponse(message);
	}

	/**
	 * @param message
	 * @param resourceInfos
	 * @see com.mas.session.state.AbstractState#waitForProposalResponse(jade.lang.acl.ACLMessage)
	 */
	public void waitForProposalResponse(ACLMessage message,
			ResourceInfo[] resourceInfos) throws FIPAException {
		currentState.waitForProposalResponse(message);
	}

	/**
	 * @param message
	 * @see com.mas.session.state.AbstractState#rejectProposalResponse(jade.lang.acl.ACLMessage)
	 */
	public void processNewProposal(ACLMessage message) {
		currentState.processNewProposal(message);
	}

	/**
	 * @param message
	 * @see com.mas.session.state.AbstractState#rejectProposalResponse(jade.lang.acl.ACLMessage)
	 */
	public void offerNewProposal(ACLMessage message) {
		currentState.offerNewProposal(message);
	}

	/**
	 * @return the isAliveInd
	 */
	public boolean isAliveInd() {
		return isAliveInd;
	}

	/**
	 * @param isAliveInd
	 *            the isAliveInd to set
	 */
	public void setAliveInd(boolean isAliveInd) {
		this.isAliveInd = isAliveInd;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	public void logInfo(String message) {
		System.out.println(name + ":" + agent.getName() + "-->" + message);
	}

	/**
	 * @return the strategy
	 */
	public Strategy getStrategy() {
		return strategy;
	}

	/**
	 * @param strategy
	 *            the strategy to set
	 */
	public void setStrategy(Strategy strategy) {
		this.strategy = strategy;
	}

	/**
	 * @return the agent
	 */
	public Agent getAgent() {
		return agent;
	}

	
	public void setAccepted(boolean accepted) {
		this.accepted = accepted;
		
	}

	public boolean isAccepted() {
		return accepted;
	}

	public String buildUniqueID() {
		return this.getName();
		
	}

	public void setExitReason(String reasonMsg) {
		this.exitReason = reasonMsg;
		
	}

	/**
	 * @return the exitReason
	 */
	public String getExitReason() {
		return exitReason;
	}

	
	
}
